package AQS;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author: 李德才
 * @description:
 * @create: 2020-12-13 14:11
 **/
public class TestReentrantLock {

    private static volatile int i = 0;
    /**
     * ReentrantLock 可重入锁
     * https://www.liaoxuefeng.com/wiki/1252599548343744/1306580960149538
     * 从Java 5开始，引入了一个高级的处理并发的 java.util.concurrent 包，它提供了大量更高级的并发功能，能大大简化多线程程序的编写。
     * 我们知道Java语言直接提供了synchronized关键字用于加锁，但这种锁一是很重，二是获取时必须一直等待，没有额外的尝试机制。
     * java.util.concurrent.locks 包提供的 ReentrantLock 用于替代 synchronized 加锁
     * 创建锁兑现 ReentrantLock lock = new ReentrantLock();
     * 加锁  lock.lock();
     * 解锁 lock.unlock();
     */
    /**
     * ReentrantLock一般在多线程环境下使用，创建锁对象，调用lock()获取锁开始处理逻辑，处理完unlock()释放锁。
     * 注意使用的时候lock和unlock必须成对出现，不然可能出现死锁或者严重堵塞的情况
     */


    public static void reentrantLock() {
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        i++;
        lock.unlock();
        /**
         * 上面的方式和下面的方式是相同意思
         * ReentrantLock可以替代 synchronized 进行同步；
         * ReentrantLock 获取锁更安全
         * ReentrantLock 比 synchronized 更轻量级
         */
//        synchronized (TestReentrantLock.class) {
//        i++;
//        }
    }


    /**
     * 支持尝试获取锁，获取不到则会继续等待指定时间，如果确实无法获取则会返回 false,可以执行其他代码
     * 因为 synchronized 是Java语言层面提供的语法，所以我们不需要考虑异常，而 ReentrantLock 是 Java 代码实现的锁，我们就必须先获取锁，然后在 finally 中正确释放锁
     */
    public static void tryReentrantLock() {
        ReentrantLock lock = new ReentrantLock();
        try {
            if (lock.tryLock() || lock.tryLock(5, TimeUnit.SECONDS)) {
//                上述代码在尝试获取锁的时候，最多等待5秒。如果5秒后仍未获取到锁，tryLock()返回false，程序就可以做一些额外处理，而不是无限等待下去
                lock.lock();
                i++;
                System.err.println(i);
            } else {
                System.err.println("=========> 获取不到锁，自己玩去 。。。 。。。");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    /**
     * 给定参数为（true）则为公平锁，哪个线程等待的时间越长，哪个线程获得锁
     * 默认为非公平锁，线程随机获得锁
     * 线程A执行完，线程 B 等待时间最长，线程 B 执行完，线程 A 等待时间最长，所以就会出现 A-B-A-B 的现象
     */
    private static Lock lock = new ReentrantLock(true);

    public static void test() {
        for (int i = 0; i < 5; i++) {
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "获取了锁");
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }


    public static void main(String[] args) {
//        reentrantLock();
//        tryReentrantLock();
        new Thread("线程A") {
            @Override
            public void run() {
                test();
            }
        }.start();
        new Thread("线程B") {
            @Override
            public void run() {
                test();
            }
        }.start();
    }

}
